use std::sync::Arc;
use parking_lot::RwLock;
use crate::data::log_record::LogRecordPos;
use crate::db::Engine;
use crate::index::IndexIterator;
use crate::options::IteratorOptions;

/// 迭代器接口

pub struct Iterator<'a> {
    index_iter: Arc<RwLock<Box<dyn IndexIterator>>>,
    engine: &'a Engine,
}

impl Engine {
    // 获取迭代器
    pub fn iter(&self,options: IteratorOptions) -> Iterator {
        Iterator {
            index_iter: Arc::new(RwLock::new(self.index.iterator(options))),
            engine:self,
        }
    }


}

impl<'a> Iterator<'a> {
    // 回到迭代器起点，即第一个数据
    pub fn rewind(&self){
        let mut index_iter = self.index_iter.write();
        index_iter.rewind();
    }

    // 根据传入的key查找第一个大于（或者小于）等于的目标Key,根据这个key开始遍历
    fn seek(&mut self, key: Vec<u8>){
        let mut index_iter = self.index_iter.write();
        index_iter.seek(key);
    }

    // Next跳转到下一个key，返回None则说明迭代完成。
    fn next(&mut self) -> Option<(Vec<u8>, Vec<u8>)> {
        let mut index_iter = self.index_iter.write();
        let result = index_iter.next();
        match result {
            None => {None},
            Some((key,LogRecordPos)) => {
                Some((key.clone(), self.engine.get(key.clone()).expect("Failed to get key from DB")))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use crate::options::options;
    use super::*;
    #[test]
    fn test_iterator() {
        let mut opts = options::default();
        opts.dir_path = PathBuf::from("/tmp/bitcask-rs-iter-seek");
        opts.data_file_size = 64*1024*1024;
        let engine = Engine::open(opts.clone()).expect("Failed to open db engine");

        // 没有数据的情况
        let mut inter1 = engine.iter(IteratorOptions::default());
        inter1.seek(b"foo".to_vec());

        // 有一条数据的情况
        engine.put(b"name".to_vec(), b"hedong".to_vec());
        engine.put(b"sex".to_vec(), b"1".to_vec());
        let mut inter2 = engine.iter(IteratorOptions::default());
        inter2.seek(b"a".to_vec());
        println!("{:?}",inter2.next().unwrap());

        std::fs::remove_dir_all(opts.clone().dir_path).unwrap();

    }





}